#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include "myThread.hpp"
#include "Task.hpp"

using namespace ThreadMoudle;
int gDefaultNum = 5;

template <class T> // 任务类型可变
class ThreadPool
{
    bool isEmpty() // 任务列表
    {
        return _taskqueue.empty();
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }

public:
    void HandlerTask() // this
    {
        while (true)
        {
            LockQueue();
            while (isEmpty() && _isrunning) //_taskqueue为空没有要运行的任务了，但线程标识还可以运行，则阻塞它，节约cpu资源
            {
                _sleep_thread_num++;
                std::cout << "Sleep" << std::endl;
                Sleep();
                _sleep_thread_num--;
            }
            if (isEmpty() && !_isrunning) //_taskqueue为空没有要运行的任务了，并且isrunning标识让线程不要运行了
            {
                UnlockQueue();
                // std::cout << _name << " exit" << std::endl;
                break;
            }
            //_taskqueue非空,  线程处理任务
            T t = _taskqueue.front();
            _taskqueue.pop();
            UnlockQueue();
            t.Debug(); // 任务已经取出---t是在线程创建的局部变量，是在线程自己的栈中开辟的空间，不涉及共享资源，所以处理任务可以放在临界区外增加并发度
            t.Execute();
            std::cout << t.Result() << std::endl;
        }
    }

public:
    ThreadPool(int thread_num = gDefaultNum)
        : _thread_num(thread_num), _sleep_thread_num(thread_num), _isrunning(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    void Init() // 初始化线程池
    {
        func_t func = std::bind(&ThreadPool::HandlerTask, this); // func是函数指针对象
        for (int i = 0; i < _thread_num; i++)
        {
            std::string name = "thread-" + std::to_string(i);
            _threadpool.emplace_back(name, func); // 依次创建并初始化myThread线程对象
        }
    }
    void Start() // 延迟真正创建/运行线程
    {
        _isrunning = true;
        for (auto &thread : _threadpool)
        {
            thread.Start();
            // std::cout << thread._name << " create success" << std::endl;
        }
    }
    void Enqueue(T *in) // 推送任务
    {
        LockQueue();
        if (_isrunning)
        {
            _taskqueue.push(*in);
            if (_sleep_thread_num > 0) // 来了一个任务，如果又休眠线程，唤醒一个来接受它
            {
                WakeUp();
            }
        }
        UnlockQueue();
    }
    void Stop() // 停止推送，处理完剩下的任务后，所有线程退出
    {
        LockQueue();
        _isrunning = false;
        WakeupAll(); // 唤醒所有线程，处理完剩下的任务后，所有线程退出; 如果一个线程在休眠那也它也无法退出了（因为没运行）
        UnlockQueue();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int _thread_num;
    int _sleep_thread_num;
    bool _isrunning;
    std::vector<myThread> _threadpool;
    std::queue<T> _taskqueue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond; // 条件变量
};